﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using Pavilion.DesignerTool.ViewTools.ConnectableListBox;
using Pavilion.DesignerTool.ViewTools;

namespace Pavilion.DesignerTool
{
    /// <summary>
    /// Interaction logic for GameToolDataView.xaml
    /// </summary>
    public partial class GameDataEditorView : UserControl
    {
        public GameDataEditorViewModel ViewModel { get; set; }

        public GameDataEditorView()
        {
            InitializeComponent();

            if (!DesignerProperties.GetIsInDesignMode(this))
                propertyGrid.DataContext = DataContext = ViewModel = new GameDataEditorViewModel();
        }

        public void SetGameData(NodeBaseWrapper nodeBaseWrapper)
        {
            ViewModel.NodeBaseWrapper = nodeBaseWrapper;
            
            if (ViewModel.NodeBaseWrapper != null && ViewModel.NodeBaseWrapper.Node is AnimationNode)
                animationPanel.Visibility = Visibility.Visible;
            else
                animationPanel.Visibility = Visibility.Collapsed;
        }

        private void AddGameDataMenuItem_Click(object sender, RoutedEventArgs e)
        {
            Type type = (e.OriginalSource as FrameworkElement).DataContext as Type;

            if (type != null)
                ViewModel.AddGameData(new GameData() { GameToolName = type.Name });
        }

        private void RemoveGameDataMenuItem_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.RemoveGameDataCategory((sender as FrameworkElement).DataContext as PropertyCategory);
        }

        private void AddPropertyMenuItem_Click(object sender, RoutedEventArgs e)
        {
            if (e.OriginalSource == sender)
                return;

            MenuItem menuItem = e.OriginalSource as MenuItem;
            PropertyCategory propertyCategory = (sender as FrameworkElement).DataContext as PropertyCategory;
            (propertyCategory.AssociatedItem as GameDataWrapper).AddProperty((string)menuItem.Header);
            ViewModel.UpdateGameDataProperties();
        }

        private void RemovePropertyMenuItem_Click(object sender, RoutedEventArgs e)
        {
            PropertyItemBase propertyItem = (sender as FrameworkElement).DataContext as PropertyItemBase;
            (propertyItem.AssociatedItem as GameDataWrapper).RemoveProperty(propertyItem.PropertyName);
            ViewModel.UpdateGameDataProperties();
        }

        private void GameItemMenuItem_Click(object sender, RoutedEventArgs e)
        {
            if (e.OriginalSource == sender)
                return;

            MenuItem menuItem = e.OriginalSource as MenuItem;
            PropertyCategory propertyCategory = (sender as FrameworkElement).DataContext as PropertyCategory;
            GameItem gameItem = (menuItem.Header as GameItemWrapper).GameItem;
            string gameItemName = (gameItem != null) ? gameItem.Name : "";
            (propertyCategory.AssociatedItem as GameDataWrapper).SetGameItemName(gameItemName);
        }
    }

    public class GameDataEditorViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public AnimationData SelectedAnimation { get { return GetSelectedAnimation(); } set { SetSelectedAnimation(value); } }
        public NodeBaseWrapper NodeBaseWrapper { get { return nodeBaseWrapper; } set { SetNodeBaseWrapper(value); OnPropertyChanged("AnimationCollection"); } }
        public IEnumerable<Type> GameDataTypeCollection { get { return GameEngine.ObtainAllTypes<GameToolBase>("Pavilion.GameTools.dll"); } }
        public NotifiableCollection<PropertyCategory> Properties { get; private set; }
        public NotifiableCollection<AnimationData> AnimationCollection { get { return (NodeBaseWrapper == null) ? null : NodeBaseWrapper.NodeScriptWrapper.ResourceData.AnimationDataCollection; } }

        private NodeBaseWrapper nodeBaseWrapper;

        public GameDataEditorViewModel()
        {
            Properties = new NotifiableCollection<PropertyCategory>();
        }

        public void UpdateGameDataProperties()
        {
            Properties.Clear();

            if (nodeBaseWrapper == null)
                return;

            foreach (GameDataWrapper gameDataWrapper in NodeBaseWrapper.GameDataWrapperCollection)
                LoadPropertiesForGameData(gameDataWrapper);
        }

        public void AddGameData(GameData gameData)
        {
            if (nodeBaseWrapper == null)
                return;
            GameDataWrapper gameDataWrapper = nodeBaseWrapper.AddGameData(gameData);

            LoadPropertiesForGameData(gameDataWrapper);
        }

        public void RemoveGameDataCategory(PropertyCategory category)
        {
            GameDataWrapper gameDataWrapper = category.AssociatedItem as GameDataWrapper;

            nodeBaseWrapper.RemoveGameData(gameDataWrapper);
            Properties.Remove(category);
        }

        private void LoadPropertiesForGameData(GameDataWrapper gameDataWrapper)
        {
            PropertyCategory propertyCategory = new PropertyCategory(gameDataWrapper);

            foreach (string propertyName in gameDataWrapper.PropertiesCollection)
                propertyCategory.AddProperty(new GameDataPropertyItem(gameDataWrapper, propertyName));

            Properties.Add(propertyCategory);
        }

        private void SetSelectedAnimation(AnimationData value)
        {
            if (NodeBaseWrapper is AnimationNodeWrapper)
                (NodeBaseWrapper as AnimationNodeWrapper).AssociatedAnimation = value;
        }

        private AnimationData GetSelectedAnimation()
        {
            if (NodeBaseWrapper is AnimationNodeWrapper)
                return (NodeBaseWrapper as AnimationNodeWrapper).AssociatedAnimation;
            else
                return null;
        }

        private void SetNodeBaseWrapper(NodeBaseWrapper value)
        {
            if (nodeBaseWrapper != null)
                nodeBaseWrapper.ParentContainerNodeWrapper.NodeWrapperRemoved -= new Action<DesignerTool.NodeBaseWrapper>(ParentContainerNodeWrapper_NodeWrapperRemoved);

            nodeBaseWrapper = value;

            if (nodeBaseWrapper != null)
                nodeBaseWrapper.ParentContainerNodeWrapper.NodeWrapperRemoved += new Action<DesignerTool.NodeBaseWrapper>(ParentContainerNodeWrapper_NodeWrapperRemoved);

            UpdateGameDataProperties();

            OnPropertyChanged("NodeBaseWrapper");
            OnPropertyChanged("SelectedAnimation");
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        private void ParentContainerNodeWrapper_NodeWrapperRemoved(NodeBaseWrapper nodeWrapper)
        {
            if (this.NodeBaseWrapper == nodeWrapper)
                this.NodeBaseWrapper = null;
        }
    }

    public class GameDataPropertyItem : PropertyItemBase
    {
        public override string PropertyName { get; set; }
        public override object PropertyValue { get { return gameDataWrapper.GetPropertyValue(PropertyName); } set { gameDataWrapper.SetPropertyValue(PropertyName, value); } }
        public override object AssociatedItem { get { return gameDataWrapper; } set { } }
        public override System.Windows.FrameworkElement FrameworkElement { get; set; }

        private GameDataWrapper gameDataWrapper;

        public GameDataPropertyItem(GameDataWrapper gameDataWrapper, string propertyName)
        {
            this.gameDataWrapper = gameDataWrapper;
            this.PropertyName = propertyName;

            LoadDefaultFrameworkElement();
        }
    }
}
